<?php

/**
 * @Author: gan
 * @Description: 个推推送实现
 * @File:  Push
 * @Version: 1.0.0
 * @Date: 2021/12/27 2:35 下午
 * 参考文档：https://docs.getui.com/getui/server/rest_v2/service_sdk/
 */

declare(strict_types=1);

namespace RX\Component\Push\Impl;

use RX\Enums\CommonEnum;
use RX\Enums\PushEnum;
use RX\Exception\BizException;
use RX\Helpers\DateHelper;
use RX\Helpers\StringHelper;
use RX\Traits\CurlTrait;

class GeTuiImpl implements PushInterface
{
    use CurlTrait;

    private $appKey       = '';                                            // 待发送的应用程序(appKey)，只能填一个。
    private $appId        = '';                                            // appId
    private $masterSecret = '';                                            // 主密码
    private $url          = "https://restapi.getui.com/v2/";               // 推送的地址
    private $authToken    = "";                                            // token

    public const HTTP_MSG_ARR = [
        200 => "成功",
        400 => "请求参数错误",
        401 => "请检查权限相关信息",
        403 => "请检查套餐相关权限信息",
        404 => "请检查Http路径是否正确",
        405 => "该接口不支持该方法请求",
    ];


    public const MSG_ARR = [
        // 基础返回码
        0     => "推送成功",
        1     => "推送失败",
        2     => "服务正在启动",
        301   => "请检查域名是否与appid机房匹配",
        404   => "请检查Http路径是否正确",
        405   => "方法不支持",

        // 10000 - 权限相关
        10001 => "token错误/失效",
        10002 => 'appId或ip在黑名单中',
        10003 => "接口调用过于频繁",
        10004 => "没有查询消息明细的权限",
        10005 => "每分钟调用频率超限",

        // 20000 - 参数相关
        20001 => "参数不合法",
        22001 => "定时任务已经执行，无法删除",
        22002 => "任务无效或定时任务时间不合法",
        23001 => "操作tag失败",

        // 30000 - 套餐相关，关于套餐相关的返回码，可以针对应用特殊配置，若有需要，请点击右侧“技术咨询”了解详情。
        30000 => "没有推送fast_custom_tag的权限",
        30001 => "没有修改和删除custom_tag的权限",
        30002 => "没有推送定时任务的权限",
        30003 => "app/tag 接口无权限，或tag无效",
        30004 => "tag每日推送总数超限",
        30005 => "tag长度超限(tag长度<32)",
        30006 => "fast_custom_tag次数超过每日推送总数限制",
        30007 => "app/all推送，推送次数超过每日推送总数限制，每日最多推送100次",
        30008 => "list推送次数超过每日推送总数限制，每日最多推送2000000次",
        30009 => "推送次数超过每日推送总数限制",
        30010 => "app/tag 推送次数超过每日推送总数限制",
        30011 => "设置tag次数超过每日次数限制，",
        30012 => "修改和删除tag 超过每分钟频率限制，每分钟最多操作5次",
        30013 => "推送fast_custom_tag频率超过每分钟频率限制",
        30014 => "app 推送 频率超过每分钟频率限制，每分钟最多操作5次",
        30015 => "list推送 频率超过每分钟频率限制",
        30016 => "push/tag tag个数超过限制",
        30017 => "没有查询单推实时报表的权限",
        30018 => "查询单推实时报表 频率超过每分钟频率限制",
        30019 => "系统繁忙，请稍后重试"
    ];

    public const PUSH_SINGLE_CID   = "pushToSingleByCid";
    public const PUSH_SINGLE_ALIAS = "pushToSingleByAlias";
    public const PUSH_BATCH_CID    = "pushBatchByCid";
    public const PUSH_BATCH_ALIAS  = "pushBatchByAlias";
    public const PUSH_LIST_CID     = "pushListByCid";
    public const PUSH_LIST_ALIAS   = "pushListByAlias";
    public const PUSH_ALL          = "pushAll";
    public const PUSH_TAG          = "pushByTag";
    public const PUSH_CUSTOM_TAG   = "pushByFastCustomTag";

    public const ALLOW_METHOD = [
        self::PUSH_SINGLE_CID   => "/push/single/cid",
        self::PUSH_SINGLE_ALIAS => "/push/single/alias",
        self::PUSH_BATCH_CID    => "/push/single/batch/cid",
        self::PUSH_BATCH_ALIAS  => "/push/single/batch/alias",
        self::PUSH_LIST_CID     => "/push/list/cid",
        self::PUSH_LIST_ALIAS   => "/push/list/alias",
        self::PUSH_ALL          => "/push/all",
        self::PUSH_TAG          => "/push/tag",
        self::PUSH_CUSTOM_TAG   => "/push/fast_custom_tag",
    ];

    public function __construct(array $config = [])
    {
        if (empty($config)) {
            $config = StringHelper::config('push.getui');
        }
        $this->appKey       = $config["appKey"];
        $this->appId        = $config["appId"];
        $this->masterSecret = $config["masterSecret"];
        $this->url          = $this->url . $this->appId;
    }


    /**
     * pushToSingleByCid ：向单个用户推送消息，可根据cid指定用户
     * pushToSingleByAlias : 向单个用户推送消息，可根据别名指定用户
     * pushBatchByCid：批量发送单推消息，每个cid用户的推送内容都不同的情况下，可以使用此接口
     * pushBatchByAlias：批量发送单推消息，在给每个别名用户的推送内容都不同的情况下，可以使用此接口
     * pushListByCid：对列表中所有cid进行消息推送。调用此接口前需调用创建消息接口设置消息内容。
     * pushListByAlias：对列表中所有别名进行消息推送。调用此接口前需调用创建消息接口设置消息内容。注：此接口频次限制200万次/天(和执行cid批量推共享限制)，申请修改请点击右侧“技术咨询”了解详情。
     * pushAll：对指定应用的所有用户群发推送消息。支持定时、定速功能，查询任务推送情况请见接口查询定时任务。注：此接口频次限制100次/天，每分钟不能超过5次(推送限制和接口根据条件筛选用户推送共享限制)
     * pushByTag：对指定应用的符合筛选条件的用户群发推送消息。支持定时、定速功能。注：此接口频次限制100次/天，每分钟不能超过5次(推送限制和接口执行群推共享限制)，定时推送功能需要申请开通才可以使用，申请修改请点击右侧“技术咨询”了解详情。
     * pushByFastCustomTag：根据标签过滤用户并推送。支持定时、定速功能。注：该功能需要申请相关套餐，请点击右侧“技术咨询”了解详情
     * @param array $data 请求参数
     * @return mixed
     * @throws BizException
     */
    public function push(array $data)
    {
        $token = $this->auth();
        $scene = $data["scene"] ?? self::PUSH_SINGLE_CID;
        $this->isAllow($scene);
        unset($data["scene"]);
        $header = [
            "token" => $token
        ];
        return $this->postCurl($this->url . self::ALLOW_METHOD[$scene], $data, true, 5, $header);
    }


    public function auth()
    {
        $timeStamp = DateHelper::getMicroTime();
        $sign      = hash("sha256", $this->appKey . $timeStamp . $this->masterSecret);
        $data      = [
            "sign"      => $sign,
            "timestamp" => $timeStamp,
            "appkey"    => $this->appKey,
        ];
        $rep       = $this->postCurl($this->url . "/auth", $data);
        $rep       = json_decode($rep, true);
        if (empty($rep) || $rep["code"] != 0) {
            throw new BizException(PushEnum::class, PushEnum::GET_TOKEN_ERROR, self::MSG_ARR[$rep["code"]]);
        }
        return $rep["data"]["token"];
    }

    private function isAllow($type)
    {
        if (!in_array($type, array_keys(self::ALLOW_METHOD))) {
            throw new BizException(CommonEnum::class, CommonEnum::INVALID_PARAMS);
        }
    }
}
